package comp302.prototype.slide.handler;

import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.KeyAdapter;

import comp302.prototype.component.Component;
import comp302.prototype.component.Line;
import comp302.prototype.component.Zigzag;
import comp302.prototype.settings.ApplicationSettings;
import comp302.prototype.settings.LineSettings;
import comp302.prototype.slide.SlideItem;

public class SlideEditHandler extends KeyAdapter implements MouseListener,
		MouseMotionListener {
	private SlideItem slideItem;
	private Component tempComponent;
	private boolean editMode;
	private int x, y;

	/*
	 * Initialize SlideEditHandler to handle edit events of slideItem.
	 */
	public SlideEditHandler(SlideItem slideItem) {
		super();
		this.slideItem = slideItem;
		tempComponent = null;
		editMode = false;
	}

	/*
	 * Draw tempComponent on g.
	 */
	public void drawTemp(Graphics g) {

		if (tempComponent != null) {
			tempComponent.draw(g);
		}
	}

	/*
	 * Handle mouse click event.
	 * 
	 * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent)
	 */
	@Override
	public void mouseClicked(MouseEvent e) {
		slideItem.requestFocus();

		if (editMode) {
			handleEditClick(e);
		} else {
			handleNormalClick(e);
		}
	}

	/*
	 * Handle clicks done outside edit mode.
	 */
	private void handleNormalClick(MouseEvent e) {
		x = e.getX();
		y = e.getY();

		if (e.getButton() != MouseEvent.BUTTON1) {
			return;
		}

		tempComponent = null;
		editMode = true;

		switch (ApplicationSettings.getCurrentTool()) {
		/*
		 * Handle select tool's initial click.
		 */
		case ApplicationSettings.SELECT_TOOL:
			ComponentHandler ch = slideItem.getComponentHandler();

			for (int i = ch.componentCount() - 1; i >= 0; i--) {
				Component component = ch.componentAt(i);

				if (component.isPointInside(new Point(x, y))
						&& component.select(x, y)) {
					switchTool(component.getName());
					tempComponent = component;
					slideItem.repaint();
					return;
				}
			}
			editMode = false;
			return;
			/*
			 * Handle line tool's initial click.
			 */
		case ApplicationSettings.LINE_TOOL:
			tempComponent = new Line(x, y, x, y, LineSettings.getColor(),
					LineSettings.getThickness());
			break;
		/*
		 * Handle zigzag tool's initial click.
		 */
		case ApplicationSettings.ZIGZAG_TOOL:
			tempComponent = new Zigzag(x, y, x, y, LineSettings.getColor(),
					LineSettings.getThickness());
			break;
		/*
		 * Unkown tool.
		 */
		default:
			tempComponent = null;
			editMode = false;
			break;
		}
	}

	/*
	 * Handle clicks in edit mode.
	 */
	private void handleEditClick(MouseEvent e) {
		int x = e.getX();
		int y = e.getY();

		if (e.getButton() != MouseEvent.BUTTON1) {
			/*
			 * Handle finalizing edit mode.
			 */
			switch (ApplicationSettings.getCurrentTool()) {
			case ApplicationSettings.SELECT_TOOL:
				tempComponent.deselect();
				ApplicationSettings.showOptionPanel("selectPanel");
				break;

			case ApplicationSettings.LINE_TOOL:
				tempComponent = null;
				break;

			case ApplicationSettings.ZIGZAG_TOOL:
				((Zigzag) tempComponent).removeLast();
				slideItem.getComponentHandler().addComponent(tempComponent);
				break;

			default:
				tempComponent = null;
				break;
			}
		} else if (tempComponent != null) {
			/*
			 * Handle applied edit then continue edit mode.
			 */
			switch (ApplicationSettings.getCurrentTool()) {
			case ApplicationSettings.SELECT_TOOL:
				return;

			case ApplicationSettings.LINE_TOOL:
				slideItem.getComponentHandler().addComponent(tempComponent);
				break;

			case ApplicationSettings.ZIGZAG_TOOL:
				((Zigzag) tempComponent).addPoint(x, y);
				return;

			default:
				slideItem.getComponentHandler().addComponent(tempComponent);
				break;
			}
		}

		tempComponent = null;
		editMode = false;
		slideItem.repaint();
	}

	@Override
	public void mouseEntered(MouseEvent e) {
	}

	@Override
	public void mouseExited(MouseEvent e) {
	}

	@Override
	public void mousePressed(MouseEvent e) {
	}

	@Override
	public void mouseReleased(MouseEvent e) {
	}

	@Override
	public void mouseDragged(MouseEvent e) {

		if (editMode
				&& e.getButton() == MouseEvent.BUTTON1
				&& ApplicationSettings.getCurrentTool() == ApplicationSettings.SELECT_TOOL
				&& tempComponent != null) {
			int dx = e.getX() - x;
			int dy = e.getY() - y;

			tempComponent.move(dx, dy);

			if (!tempComponent.boundaryCheck(slideItem.getWidth(),
					slideItem.getHeight())) {
				tempComponent.move(-dx, -dy);
			}
			slideItem.repaint();
			x = e.getX();
			y = e.getY();
		}
	}

	@Override
	public void mouseMoved(MouseEvent e) {

		if (!editMode) {
			return;
		}

		x = e.getX();
		y = e.getY();

		switch (ApplicationSettings.getCurrentTool()) {
		case ApplicationSettings.LINE_TOOL:
			((Line) tempComponent).setEndPoint(x, y);
			break;

		case ApplicationSettings.ZIGZAG_TOOL:
			((Zigzag) tempComponent).setEndPoint(x, y);
			break;

		default:
			break;
		}
		slideItem.repaint();
	}

	@Override
	public void keyPressed(KeyEvent evt) {

		if (editMode
				&& evt.getKeyChar() == '\b'
				&& ApplicationSettings.getCurrentTool() == ApplicationSettings.SELECT_TOOL
				&& tempComponent != null) {
			ComponentHandler ch = slideItem.getComponentHandler();

			tempComponent.deselect();
			ApplicationSettings.showOptionPanel("selectPanel");
			ch.removeComponentAt(ch.indexOf(tempComponent));
			tempComponent = null;
			editMode = false;
			slideItem.repaint();
		}
	}

	private void switchTool(String componentName) {
		String panelName = componentName.toLowerCase() + "Panel";

		if (panelName.equals("zigzagPanel")) {
			panelName = "linePanel";
		}
		ApplicationSettings.showOptionPanel(panelName);
	}

	public void updateTempAttributes() {

		if (tempComponent == null) {
			return;
		} else {
			tempComponent.updateAttributes();
			slideItem.repaint();
		}
	}

	public void clearState() {

		if (tempComponent != null) {
			tempComponent.deselect();
			tempComponent = null;
		}
		editMode = false;
		slideItem.repaint();
	}
}
